﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

using ApplicationBoilerplate.DataProvider;

using MongoDB.Driver;
using MongoDB.Driver.Builders;
using MongoDB.Driver.Linq;

namespace MVCBootstrap.MongoDB {

	public class Repository<TEntity> : RepositoryBase<TEntity> where TEntity : class {
		protected readonly MongoCollection<TEntity> collection;

		public Repository(MongoCollection<TEntity> collection) {
			this.collection = collection;
		}

		public override TEntity Create(TEntity newEntity) {
			this.collection.Insert<TEntity>(newEntity);
			return newEntity;
		}

		public override TEntity Read(String id) {
			return this.collection.FindOneByIdAs<TEntity>(id);
		}

		public override TEntity Read(Int32 id) {
			return this.collection.FindOneByIdAs<TEntity>(id);
		}

		public override TEntity Read(Guid id) {
			return this.collection.FindOneByIdAs<TEntity>(id);
		}

		public override TEntity Update(TEntity entity) {
			this.collection.Save<TEntity>(entity);
			return entity;
		}

		public override void Delete(TEntity entity) {
			throw new NotImplementedException();
		}

		public override void Delete(String id) {
			this.collection.Remove(Query.EQ("_id", id));
		}

		public override void Delete(Int32 id) {
			this.collection.Remove(Query.EQ("_id", id));
		}

		public override void Delete(Guid id) {
			this.collection.Remove(Query.EQ("_id", id));
		}

		public override IEnumerable<TEntity> ReadAll() {
			return this.collection.FindAllAs<TEntity>().AsQueryable();
		}

		public override TEntity ReadOne(ISpecification<TEntity> spec) {
			return this.ReadOne(spec.IsSatisfied);
		}

		public override TEntity ReadOne(Expression<Func<TEntity, Boolean>> criteria) {
			return this.collection.AsQueryable<TEntity>().Where(criteria).FirstOrDefault();
		}

		public override IEnumerable<TEntity> ReadMany(ISpecification<TEntity> spec) {
			return this.ReadMany(spec.IsSatisfied);
		}

		public override IEnumerable<TEntity> ReadMany(Expression<Func<TEntity, Boolean>> criteria) {
			return this.collection.AsQueryable<TEntity>().Where(criteria);
		}
	}
}